#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <getopt.h>
#define DISK_SDA  8
#define DISK_DM   251
#define DISK_VD   253
#define DISK_NVME 259
#define DISK_HDD  65
#define DISK_HDD1  66
#define DISK_HDD2  67
#define DISK_HDD3  68
#define DISK_SDA_NUM   40
#define DISK_HDD_NUM   60
#define DISK_HDD_SUBNUM  15
#define DISK_DM_NUM    16
#define DISK_VD_NUM    80
#define DISK_NVME_NUM  80
#define DISK_TOTAL_NUM (DISK_SDA_NUM + DISK_HDD_NUM + DISK_DM_NUM + DISK_VD_NUM + DISK_NVME_NUM)
#define PRINT_SYSCALL_NUM  12
#define PRINT_MORE_NUM  12
#define TRACK_SYSCALL_NUM (PRINT_SYSCALL_NUM + PRINT_MORE_NUM + DISK_TOTAL_NUM)
struct func_latency {
    unsigned long nr;
    unsigned long num;
    unsigned long latency;
    unsigned long block_latency;
    char func[256];
};

int control_os_stat(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/control_stat", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, sizeof(*buf));

	lseek(fd, 0, SEEK_SET);

	ret = read(fd, buf, sizeof(*buf));
	if (ret <= 0) {
		printf("read error:%d\n", ret);
		close(fd);
		return ret;
	}

	close(fd);
	return ret;
}
int enable_track_proc(char *proc)
{
	int ret, fd;


	fd = open("/proc/sys/os_aware/proc_comm", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, proc, strlen(proc));

	close(fd);
	return ret;
}
int enable_block_stat(int block)
{
	char buf[4] = {'1'}, ret, fd;

	if (block == 0)
	  return 0;

	fd = open("/proc/sys/os_aware/enable_stat_block", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, sizeof(*buf));

	close(fd);
	return ret;
}
int enable_sys_stat()
{
	char buf[4] = {'1'}, ret, fd;

	fd = open("/proc/sys/os_aware/system_hook_function", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, sizeof(*buf));

	close(fd);
	return ret;
}
int disable_sys_stat()
{
	char buf[4] = {'1'}, ret, fd;

	fd = open("/proc/sys/os_aware/system_unhook_function", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, sizeof(*buf));

	close(fd);
	return ret;
}
int enable_os_stat()
{
	char buf[4] = {'1'}, ret, fd;

	fd = open("/proc/sys/os_aware/enable", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, sizeof(*buf));

	lseek(fd, 0, SEEK_SET);

	ret = read(fd, buf, sizeof(*buf));
	if (ret <= 0) {
		printf("read error:%d\n", ret);
		close(fd);
		return ret;
	}


	close(fd);
	return ret;
}

int register_kret_ftrace_func(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/kprobe_register_func", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);
	return ret;
}

int unregister_one_func(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/kprobe_unregister_func", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);
	return ret;
}
int get_register_status(void)
{
	int ret, fd;
	char success[4];

	fd = open("/proc/sys/os_aware/kret_probe_success", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return 0;
	}

	ret = read(fd, success, sizeof(success));

	close(fd);

	if (ret > 0 && (atoi(success) == 1))
		return 1;


	fd = open("/proc/sys/os_aware/ftrace_success", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return 0;
	}

	ret = read(fd, success, sizeof(success));

	close(fd);

	if (ret > 0 && atoi(success) == 2)
	  return 1;

	return 0;
}

int register_ftrace_func(char *buf)
{
	int ret, fd, i;
	char success[4];

	fd = open("/proc/sys/os_aware/ftrace_hook_function", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);


	fd = open("/proc/sys/os_aware/ftrace_success", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}
	for (i = 0; i < 20; i++) {

	    ret = read(fd, success, sizeof(success));
	    if (ret <= 0)
		    return -EINVAL;

	    if (atoi(success) == 2)
		    break;

	    lseek(fd, 0, SEEK_SET);
	    usleep(20000);
	}

	close(fd);

	if (atoi(success) != 2)
		ret = -EINVAL;

	return ret;
}

int register_one_ftrace_func(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/ftrace_hook_one_function", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);
	return ret;
}

int unregister_ftrace_func(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/ftrace_unhook_function", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);
	return ret;
}

int read_one_func_data(struct func_latency *test_data, int func_num)
{
	int fd, ret;

	fd = open("/proc/sys/os_aware/func_data", O_RDONLY);
	if (fd < 0) {
		printf("open func_data error:%d\n", fd);
		return 0;
	}

	ret = read(fd, test_data, func_num * sizeof(struct func_latency));
	if (ret <= 0)
		printf("read func_data error:%d, %d\n", ret, func_num);

	close(fd);
	return ret;
}

int write_func_pointer(char *buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/write_func_pointer", O_RDWR);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = write(fd, buf, strlen(buf));

	close(fd);
	return ret;
}

int get_func_pointer(char **buf)
{
	int ret, fd;

	fd = open("/proc/sys/os_aware/get_func_pointer", O_RDONLY);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return fd;
	}

	ret = read(fd, *buf, 64);

	close(fd);
	return ret;
}

int process_func_pointer(char *name, char *parent_name, char *origin_name)
{
	int ret;
	char buf[4] = {'2'};
	char *ptr;

	if (!strstr(name, "->") && !strstr(name, "INDIRECT_CALL_INET") && !strstr(name, "INDIRECT_CALL_2"))
		return 0;
	if (strstr(parent_name, "->"))
		return -1;

	ret = register_ftrace_func(parent_name);
	if (ret < 0)
		goto return_ret;

	write_func_pointer(name);

	control_os_stat(buf);
	usleep(1000000);

	ret = get_func_pointer(&origin_name);

	memset(buf, '0', sizeof(*buf));
	control_os_stat(buf);

	ptr = strchr(origin_name, '+');
	if (ptr)
	  *ptr = '\0';
return_ret:
	unregister_ftrace_func(parent_name);

	return ret;
}
void data_sort(struct func_latency arr[], int len)
{
    unsigned long total_num = 0, total_latency = 0;
    unsigned long total_block_latency = 0, min, max, ave;
    int i, p90, p95, p99;

    for (i = 0; i < len - 8; i++) {
        for (int j = 0; j < len - 8 - i; j++) {
            if (arr[j].latency > arr[j + 1].latency) {
                unsigned long latency = arr[j].latency;
                unsigned long num = arr[j].num;
                unsigned long block_latency = arr[j].block_latency;
                arr[j].latency = arr[j + 1].latency;
                arr[j + 1].latency = latency;
                arr[j].num = arr[j + 1].num;
                arr[j + 1].num = num;
                arr[j].block_latency = arr[j + 1].block_latency;
                arr[j + 1].block_latency = block_latency;
            }
        }
    }
    for (i = 0; i < len - 8; i++) {
	total_num += arr[i].num;
	total_latency += arr[i].num * arr[i].latency;
	total_block_latency += arr[i].num * arr[i].block_latency;
	if (arr[i].latency > arr[len - 7].latency) {
	    arr[len - 7].num = arr[i].num;
	    arr[len - 7].latency = arr[i].latency;
	    arr[len - 7].block_latency = arr[i].block_latency;
	}
	if (arr[len - 6].latency == 0 || arr[i].latency < arr[len - 6].latency) {
	    arr[len - 6].num = arr[i].num;
	    arr[len - 6].latency = arr[i].latency;
	    arr[len - 6].block_latency = arr[i].block_latency;
	}
    }
    arr[len - 5].num = total_num;
    arr[len - 5].latency = total_latency;
    arr[len - 5].block_latency = total_block_latency;
    if (total_num == 0)
	total_num = 1;
    arr[len - 4].num = total_num;
    arr[len - 4].latency = total_latency / total_num;
    arr[len - 4].block_latency = total_block_latency / total_num;

    p90 = (len - 8) * 9 / 10;
    for (i = 0; i <= p90; i++ )
      arr[len - 3].num += arr[i].num;
    arr[len - 3].latency = arr[p90].latency;
    arr[len - 3].block_latency = arr[p90].block_latency;

    p95 = (len - 8) * 95 / 100;
    for (i = 0; i <= p95; i++ )
      arr[len - 2].num += arr[i].num;
    arr[len - 2].latency = arr[p95].latency;
    arr[len - 2].block_latency = arr[p95].block_latency;

    p99 = (len - 8) * 99 / 100;
    for (i = 0; i <= p99; i++ )
      arr[len - 1].num += arr[i].num;
    arr[len - 1].latency = arr[p99].latency;
    arr[len - 1].block_latency = arr[p99].block_latency;
}
#define NAME_LENGTH 256
int main(int argc,char *argv[])
{
	int fd, ret, i, func_ret, j;
	struct func_latency data[TRACK_SYSCALL_NUM];
	struct func_latency func_data;
	char buf[4] = {'1'};
	char name[256] = "vfs_read";
	char origin[256] = "vfs_read";
	char proc[256] = "0";
	unsigned long func_ptr;
	int  func_num = 1;
	int  func_total = 0;
	char parent_name[64] = "vfs_read";
	char grand_parent_name[64] = "vfs_read";
	char *more_name;
	int print = 1;
	int delay = 5, delay_once_us = 10000, tmp_delay;
	int block = 0, delay_cycle = 1, index = 0;
	int nr_node = 0, hot = 0;
	struct func_latency *test_data;
	int register_status;
	int pointer = 2;

	int opt;
	char *string = "0:1:2:3:4:5:6:7:8:9:f:n:i:t:b:h:p:x";
	struct option longopts[] = {
	    {"10",    1,       NULL, 'a'},
	    {"11",    1,       NULL, 'g'},
	    {"12",    1,       NULL, 'c'},
	    {"13",    1,       NULL, 'd'},
	    {"14",    1,       NULL, 'e'},
	    {"15",    1,       NULL, 'j'},
	    {"16",    1,       NULL, 'k'},
	    {"17",    1,       NULL, 'l'},
	    {"18",    1,       NULL, 'm'},
	    {"19",    1,       NULL, 'o'},
	    {"20",    1,       NULL, 'q'},
	    {"21",    1,       NULL, 'r'},
	    {"22",    1,       NULL, 's'},
	    {"23",    1,       NULL, 'u'},
	    {"24",    1,       NULL, 'v'},
	    {"25",    1,       NULL, 'w'},
	    {"26",    1,       NULL, 'y'},
	    {"27",    1,       NULL, 'z'},
	    {"28",    1,       NULL, '~'},
	    {"29",    1,       NULL, '!'},
	    {"30",    1,       NULL, '@'},
	    {"31",    1,       NULL, '#'},
	    {"32",    1,       NULL, '$'},
	    {"33",    1,       NULL, '%'},
	    {"34",    1,       NULL, '^'},
	    {"35",    1,       NULL, '&'},
	    {"36",    1,       NULL, '*'},
	    {"37",    1,       NULL, '('},
	    {"38",    1,       NULL, ')'},
	    {"39",    1,       NULL, '-'},
	    {"40",    1,       NULL, '+'},
	    {"ptr",   1,       NULL, '_'},
	    {0,         0,                 0,      0},
	};


	more_name = (char *)malloc(50 * NAME_LENGTH);
	if (!more_name)
	    return -ENOMEM;

	while ((opt = getopt_long(argc, argv, string, longopts, NULL))!= -1) {
	    switch (opt) {
	    case 'f':
	    case '0':
	      func_ptr = optarg;
	      strcpy(origin, optarg);
	      strcpy(name, optarg);
	      strcpy(&more_name[0], optarg);
	      func_total++;
	      break;
	    case '1':
	      strcpy(parent_name, optarg);
	      strcpy(&more_name[NAME_LENGTH], optarg);
	      func_total++;
	      break;
	    case '2':
	      strcpy(grand_parent_name, optarg);
	      strcpy(&more_name[NAME_LENGTH * 2], optarg);
	      func_total++;
	      break;
	    case '3':
	      strcpy(&more_name[NAME_LENGTH * 3], optarg);
	      func_total++;
	      break;
	    case '4':
	      strcpy(&more_name[NAME_LENGTH * 4], optarg);
	      func_total++;
	      break;
	    case '5':
	      strcpy(&more_name[NAME_LENGTH * 5], optarg);
	      func_total++;
	      break;
	    case '6':
	      strcpy(&more_name[NAME_LENGTH * 6], optarg);
	      func_total++;
	      break;
	    case '7':
	      strcpy(&more_name[NAME_LENGTH * 7], optarg);
	      func_total++;
	      break;
	    case '8':
	      strcpy(&more_name[NAME_LENGTH * 8], optarg);
	      func_total++;
	      break;
	    case '9':
	      strcpy(&more_name[NAME_LENGTH * 9], optarg);
	      func_total++;
	      break;
	    case 'a':
	      strcpy(&more_name[NAME_LENGTH * 10], optarg);
	      func_total++;
	      break;
	    case 'g':
	      strcpy(&more_name[NAME_LENGTH * 11], optarg);
	      func_total++;
	      break;
	    case 'c':
	      strcpy(&more_name[NAME_LENGTH * 12], optarg);
	      func_total++;
	      break;
	    case 'd':
	      strcpy(&more_name[NAME_LENGTH * 13], optarg);
	      func_total++;
	      break;
	    case 'e':
	      strcpy(&more_name[NAME_LENGTH * 14], optarg);
	      func_total++;
	      break;
	    case 'j':
	      strcpy(&more_name[NAME_LENGTH * 15], optarg);
	      func_total++;
	      break;
	    case 'k':
	      strcpy(&more_name[NAME_LENGTH * 16], optarg);
	      func_total++;
	      break;
	    case 'l':
	      strcpy(&more_name[NAME_LENGTH * 17], optarg);
	      func_total++;
	      break;
	    case 'm':
	      strcpy(&more_name[NAME_LENGTH * 18], optarg);
	      func_total++;
	      break;
	    case 'o':
	      strcpy(&more_name[NAME_LENGTH * 19], optarg);
	      func_total++;
	      break;
	    case 'q':
	      strcpy(&more_name[NAME_LENGTH * 20], optarg);
	      func_total++;
	      break;
	    case 'r':
	      strcpy(&more_name[NAME_LENGTH * 21], optarg);
	      func_total++;
	      break;
	    case 's':
	      strcpy(&more_name[NAME_LENGTH * 22], optarg);
	      func_total++;
	      break;
	    case 'u':
	      strcpy(&more_name[NAME_LENGTH * 23], optarg);
	      func_total++;
	      break;
	    case 'v':
	      strcpy(&more_name[NAME_LENGTH * 24], optarg);
	      func_total++;
	      break;
	    case 'w':
	      strcpy(&more_name[NAME_LENGTH * 25], optarg);
	      func_total++;
	      break;
	    case 'y':
	      strcpy(&more_name[NAME_LENGTH * 26], optarg);
	      func_total++;
	      break;
	    case 'z':
	      strcpy(&more_name[NAME_LENGTH * 27], optarg);
	      func_total++;
	      break;
	    case '~':
	      strcpy(&more_name[NAME_LENGTH * 28], optarg);
	      func_total++;
	      break;
	    case '!':
	      strcpy(&more_name[NAME_LENGTH * 29], optarg);
	      func_total++;
	      break;
	    case '@':
	      strcpy(&more_name[NAME_LENGTH * 30], optarg);
	      func_total++;
	      break;
	    case '#':
	      strcpy(&more_name[NAME_LENGTH * 31], optarg);
	      func_total++;
	      break;
	    case '$':
	      strcpy(&more_name[NAME_LENGTH * 32], optarg);
	      func_total++;
	      break;
	    case '%':
	      strcpy(&more_name[NAME_LENGTH * 33], optarg);
	      func_total++;
	      break;
	    case '^':
	      strcpy(&more_name[NAME_LENGTH * 34], optarg);
	      func_total++;
	      break;
	    case '&':
	      strcpy(&more_name[NAME_LENGTH * 35], optarg);
	      func_total++;
	      break;
	    case '*':
	      strcpy(&more_name[NAME_LENGTH * 36], optarg);
	      func_total++;
	      break;
	    case '(':
	      strcpy(&more_name[NAME_LENGTH * 37], optarg);
	      func_total++;
	      break;
	    case ')':
	      strcpy(&more_name[NAME_LENGTH * 38], optarg);
	      func_total++;
	      break;
	    case '-':
	      strcpy(&more_name[NAME_LENGTH * 39], optarg);
	      func_total++;
	      break;
	    case '+':
	      strcpy(&more_name[NAME_LENGTH * 40], optarg);
	      func_total++;
	      break;
	    case 'n':
	      func_num  = atoi(optarg);
	      break;
	    case 'i':
	      print = atoi(optarg);
	      break;
	    case 't':
	      delay = atoi(optarg);
	      break;
	    case 'b':
	      block = atoi(optarg);
	      break;
	    case 'h':
	      hot = atoi(optarg);
	      break;
	    case 'p':
	       strcpy(proc, optarg);
	       break;
	    case '_':
	       pointer = atoi(optarg);
	       break;
	    default:
	       break;
	    }
	}

	ret = enable_os_stat();
	if (ret <= 0) {
		printf("enable error:%d\n", ret);
		return 0;
	}

	while (1) {
		register_status = get_register_status();
		if (!register_status)
		  break;
	}
	enable_track_proc(proc);
	enable_block_stat(block);

	if (pointer == 0)
		goto not_pointer;

	if (!print)
		goto print_one;

	enable_sys_stat();
	fd = open("/proc/sys/os_aware/data", O_RDONLY);
	if (fd < 0) {
		printf("open error:%d\n", fd);
		return 0;
	}

	memset(data, 0, TRACK_SYSCALL_NUM * sizeof(struct func_latency));

	sleep(delay);

	ret = read(fd, data, TRACK_SYSCALL_NUM * sizeof(struct func_latency));
	if (ret <= 0)
		printf("read error:%d\n", ret);

	printf("\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
	printf("\033[22;35m<< Only block ave delay is longer than before, maybe: mutex/sem lock contention or wait for resource, need to see the block pos          >>\033[0m\n");
	printf("\033[22;35m<< AVE delay is longer than before, maybe: spin lock contention or more process running or code need improved, need to see the block pos >>\033[0m\n");
	printf("\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< syscall stat >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
	if (ret > 0) {
		for (i = 0; i < PRINT_SYSCALL_NUM; i++)
			printf("\033[1;32m nr:%4ld, num:%8ld, ave latency:%8ld(ns), block ave latency:%8ld(ns) %s\033[0m\n", data[i].nr, data[i].num, data[i].latency, data[i].block_latency, data[i].func);

		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 0 */
		printf("\n\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[22;35m<<<<<<<<<<<<<<<<<<< access vm >>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[1;32m num:%8ld, block ave latency:%8ld(ns) fuzzy stat:%s\033[0m\n", data[i].num, data[i].block_latency, data[i].func);
		i++;

		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 1 */
		printf("\n\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[22;35m<<<<<<<<<<<<<<<<<<<<< irq >>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[1;32m num :%8ld,      irq latency :%8ld(ns)      %s\033[0m\n", data[i].nr, data[i].latency, data[i].func);
		printf("\033[1;32m num :%8ld,  softirq latency :%8ld(ns)      softirq stat\033[0m\n", data[i].num, data[i].block_latency);
		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 2 */
		i++;
		printf("\n\033[22;35m <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[22;35m <<<<<< for numa: numa distribution maybe used with rq running num per node           >>>>>\033[0m\n");
		printf("\033[22;35m <<<<<< for syscall/fs: location performance caused by memory allocation or bio or fs >>>>>\033[0m\n");
		printf("\033[22;35m <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< memory >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\033[0m\n");

		printf("\033[1;32m num :%8ld, not hit num:%8ld,      ave latency :%8ld(ns), block ave latency:%8ld(ns), %s\033[0m\n\n", data[i].nr, data[i].num, data[i].latency, data[i].block_latency, data[i].func);

		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 3 */
		i++;
		j = 0;
		printf("\033[1;32m num :%8ld, size:%8ld(k), block ave time:%8ld(ns), %s\033[0m\n\n", data[i].nr, data[i].num, data[i].block_latency, data[i].func);
		i++;

		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 4, +5 */
		for (;i < PRINT_SYSCALL_NUM + PRINT_MORE_NUM - 2; i++) {
		  printf("\033[1;32m num :%8ld, mem :%8ld(k), block ave time:%8ld(ns), node:%8ld, %s\033[0m\n", data[i].num, data[i].latency, data[i].block_latency, data[i].nr, data[i].func);
		  j++;
		  if (j >= 2) {
		      i++;
		      break;
		  }
		}
		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 6, +7 */
		printf("\n\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[22;35m<<<<<<<<<<<<<<<< rq running num >>>>>>>>>>>>>>>\033[0m\n", i);
		j = 0;
		for (;i < PRINT_SYSCALL_NUM + PRINT_MORE_NUM; i++) {
		  printf("\033[1;32m node:%8ld, nr running:%8ld, busy:%ld, %s\033[0m\n", data[i].nr, data[i].num, data[i].latency, data[i].func);
		  j++;
		  if (j >= 2)
		    break;
		}

		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 8, +9 */
		i++;
		printf("\n\033[22;35m<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		printf("\033[22;35m<<<<<<<<<<<<<<<<<<<<< bio >>>>>>>>>>>>>>>>>>>>>\033[0m\n");
		for (j = 0; j < 2; j++) {
		    printf("\033[1;32m num :%8ld, ave latnecy      :%8ld(ns)   block ave latency:%8ld(ns)      %s\033[0m\n", data[i].num, data[i].latency, data[i].block_latency, data[i].func);
		    i++;
		}
		/* PRINT_MORE_NUM:PRINT_SYSCALL_NUM + 10, +11 */
		for (j = 0; j < 2; j++) {
		  printf("\033[1;32m num :%8ld, block ave latency:%8ld(ns)   %s\033[0m\n", data[i].num, data[i].block_latency, data[i].func);
		  i++;
		}
		for (; i < TRACK_SYSCALL_NUM; i++) {
		    if (data[i].num > 0)
			printf("\033[1;32m num :%8ld, %s\033[0m\n", data[i].num, data[i].func);
		}
	}
	close(fd);
	disable_sys_stat();

	return 0;

print_one:
	ret = process_func_pointer(name, parent_name, origin);
	if (ret < 0 || ret == 1 || !strncmp(origin, "0x0", 3)) {
	    memset(origin, 0 , 256);
	    ret = process_func_pointer(name, grand_parent_name, origin);
	}

	if (pointer == 1) {
	    printf("\033[1;32m ======:pointer:%s, current func:%s()\033[0m\n",
		name,  origin);
	    return ret;
	}

	if (ret < 0)
	  return ret;

	if (strstr(origin, "->"))
	    return 0;
not_pointer:
	tmp_delay = delay * 1000 * 1000;
	delay_cycle = 1;
	if (hot)
	    goto run_test;
	/* delay * 1000 * 1000/ 100, s->us */
	tmp_delay = delay * 10000;
	if (tmp_delay < 10000)
	    tmp_delay = 10000;
	delay_cycle = delay * 1000 * 1000 / tmp_delay;
	if (delay_cycle == 0)
	    delay_cycle = 1;

run_test:
	test_data = malloc(func_num * sizeof(struct func_latency) * (delay_cycle + 7));
	if (!test_data)
	    return 0;

	memset(test_data, "0", func_num * sizeof(sizeof(struct func_latency) * (delay_cycle + 7)));

	if (pointer == 0) {
	    if (func_total != func_num) {
		printf("func num error: get:%d, may:%d\n", func_total, func_num);
		func_total = func_total < func_num?func_total:func_num;
	    }
	    i = 1;
	    while (i < func_total) {
		register_one_ftrace_func(&more_name[i * NAME_LENGTH]);
		i++;
	    }
	    register_ftrace_func(&more_name[0]);
	} else
	    func_ret = register_kret_ftrace_func(origin);

	for (i = 0; i < 10; i++) {
	    usleep(100000);
	    register_status = get_register_status();
	    if (register_status)
	      break;
	}
	if (!register_status)
	    goto out;

	while (delay_cycle > 0) {
	    control_os_stat(buf);
	    usleep(1000);
	    control_os_stat(buf);
	    memset(buf, '0', sizeof(*buf));
	    usleep(1000);
	    control_os_stat(buf);

	    usleep(tmp_delay);

	    ret = read_one_func_data(&test_data[index], func_num);
	    if (ret < 0)
	      goto out;

	    delay_cycle--;
	    index++;
	}

	if (hot) {
	    for (i = 0; i < func_num; i++) {
		//if(test_data[i].num == 0)
		 // continue;
		printf("\033[1;32m ======:num:%8ld, ave latency:%8ld(ns), block ave latency:%8ld(ns), current func:%s()\033[0m\n",
		     test_data[i].num, test_data[i].latency, test_data[i].block_latency, test_data[i].func);
	    }
	}
	else {
	    data_sort(test_data, index + 7);

	    printf("\033[1;32m === ave ===:current func:%s(), num:%8ld, ave latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index + 3].num, test_data[index + 3].latency, test_data[index + 3].block_latency);
	    printf("\033[1;32m === max ===:current func:%s(), num:%8ld, max latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index].num, test_data[index].latency, test_data[index].block_latency);
	    printf("\033[1;32m === min ===:current func:%s(), num:%8ld, min latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index + 1].num, test_data[index + 1].latency, test_data[index + 1].block_latency);
	    printf("\033[1;32m === p90 ===:current func:%s(), num:%8ld, p90 latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index + 4].num, test_data[index + 4].latency, test_data[index + 4].block_latency);
	    printf("\033[1;32m === p95 ===:current func:%s(), num:%8ld, p95 latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index + 5].num, test_data[index + 5].latency, test_data[index + 5].block_latency);
	    printf("\033[1;32m === p99 ===:current func:%s(), num:%8ld, p99 latency:%8ld(ns), block latency:%8ld(ns)\033[0m\n",
		   test_data[0].func, test_data[index + 6].num, test_data[index + 6].latency, test_data[index + 6].block_latency);
	}

out:
	unregister_one_func(origin);

	free(test_data);
	free(more_name);
	return func_ret;
}
